import logging
import traceback

import os.path
import os
import time

import colorsys

import queVars

import random
random.seed()



class RobustFileHandler(logging.FileHandler):
	"""
	A handler class which writes formatted logging records to disk files.
	"""



	def emit(self, record):
		"""
		Emit a record.

		If the stream was not opened because 'delay' was specified in the
		constructor, open it before calling the superclass's emit.
		"""
		failures = 0
		while self.stream is None:
			try:
				self.stream = self._open()
			except:

				time.sleep(1)
				if failures > 3:
					traceback.print_exc()
					print "Cannot open log file?"
					return
				failures += 1
		failures = 0
		while failures < 3:
			try:
				logging.StreamHandler.emit(self, record)
				break
			except:
				failures += 1
				pass
		else:
			traceback.print_stack()
			print "Error writing to file?"


		self.close()

#---------------------------------------------------------------------------
#   Manager classes and functions
#---------------------------------------------------------------------------


class PrintHandler(logging.Handler):
	def __init__(self):

		#Needed to make writing to the screen atomic
		logging.Handler.__init__(self)


	def emit(self, record):

		self.acquire()

		textStr = self.format(record)
		if textStr.find("$$") + 1:
			try:
				color, string = textStr.split(":", 1)
				r, g, b = color.strip("$").split(",")
				color = (int(r), int(g), int(b))
				queVars.printFunc(string + "\n", color=color)
			except:
				queVars.printFunc(textStr + "\n")
				print "Error printing string: ", textStr

			#if queVars.printToStdout:
			#	print textStr
		else:
			queVars.printFunc(textStr + "\n")
			#if queVars.printToStdout:
			#	print textStr



		self.release()


def spacedPastels(number):
	spacing = 1.0 / number

	offset = random.random()

	value = 1
	saturation = 0.3
	outValues = []
	for x in range(number):
		r, g, b = colorsys.hsv_to_rgb((spacing * x) + offset, saturation, value)
		tup = (int(r * 255), int(g * 255), int(b * 255))
		outValues.append(tup)
	return outValues

if __name__ == "__main__":

	import matplotlib
	matplotlib.use("WxAgg")		# Change ploting backend

	import matplotlib.pyplot as pplt
	import numpy as np


	sampleRate = 1000.0
	length = 1

	inVals = np.arange(0, length, 1 / sampleRate)


	offset = random.random()

	value = 1
	saturation = 0.3

	dat = np.zeros((inVals.shape[0], 3))
	print dat.shape

	for x in range(inVals.shape[0]):
		#print x
		#print colorsys.hsv_to_rgb(inVals[x], saturation, value)
		dat[x, ...] = colorsys.hsv_to_rgb(inVals[x] + offset, saturation, value)

	vals = spacedPastels(5)
	print vals
	print "%s %s %s" % vals[0]



	mainWin = pplt.figure()
	mainWin.subplots_adjust(hspace=.4, wspace=.4)
	#Add space between subplots to make them look nicer

	numPlots = 2

	plot1 = mainWin.add_subplot(1, 1, 1)
	plot1.plot(dat)

	pplt.show()

import threading


class ThreadLog:
	def __init__(self, numLogs):

		self.printLock = threading.Lock()
		self.logInstaces = initThreadLogging(numLogs)

		self.mainLog = logging.getLogger("Main.PluginMain")

	def getLogger(self):
		threadName = threading.currentThread().name
		if threadName == "MainThread":
			threadName = "PluginMain"
		return logging.getLogger("Main.%s" % threadName)

	def reformatArgs(self, args):
		outstr = ""
		for item in args:
			outstr = "%s%s" % (outstr, item)
		return outstr

	def info(self, *args):
		self.printLock.acquire()
		tempStr = self.reformatArgs(args)
		#try:
		#	print "logging", tempStr.encode('ascii', 'xmlcharrefreplace')
		#except:
		#	print "Could not print string"
		#	self.getLogger().critical("string error")

		try:
			self.getLogger().info(self.reformatArgs(args))
		except:
			#import traceback
			#traceback.print_exc()
			print "error in logging.getLogger. Was trying to print:"
			tempStr = self.reformatArgs(args).encode('ascii', 'xmlcharrefreplace')
			try:
				print tempStr
			except:
				print "Could not print string"
				self.getLogger().critical("string error")

		self.printLock.release()

	def warning(self, *args):
		self.printLock.acquire()
		self.getLogger().warning(self.reformatArgs(args))
		self.printLock.release()

	def error(self, *args):
		self.printLock.acquire()
		self.getLogger().error(self.reformatArgs(args))
		self.printLock.release()

	def critical(self, *args):
		self.printLock.acquire()
		self.getLogger().critical(self.reformatArgs(args))
		self.printLock.release()



def initThreadLogging(numThreads, logLevel = logging.INFO, printLevel = logging.INFO):
	if not queVars.threadLogHasBeenInited:
		if numThreads > 1:
			loggerNames = []
			print "Setting up print handlers"
			colors = spacedPastels(numThreads)
			for x in range(numThreads):
				lName = "Main.Thread %d" % x
				loggerNames.append(lName)
				tLogger = logging.getLogger(lName)		# SubLogger for Plugins

				tPrintHandler = PrintHandler()
				tPrintHandler.setLevel(printLevel)
				colorFormat = "$$%s,%s,%s:" % colors[x]
				formatMap = '%s Plugin Thread %d : %%(levelname)s - %%(message)s' % (colorFormat, (x + 1))

				thFormatter = logging.Formatter(formatMap)		# Compensate for zero indexing in range()
				tPrintHandler.setFormatter(thFormatter)
				tLogger.addHandler(tPrintHandler)

		# And the main plugin print function

		lName = "Main.PluginMain"
		loggerNames = lName
		tLogger = logging.getLogger(lName)		# SubLogger for Plugins

		tPrintHandler = PrintHandler()
		tPrintHandler.setLevel(printLevel)

		formatMap = 'Plugin Main Thread: %(levelname)s - %(message)s'


		thFormatter = logging.Formatter(formatMap)		# Compensate for zero indexing in range()
		tPrintHandler.setFormatter(thFormatter)
		tLogger.addHandler(tPrintHandler)

		queVars.threadLogHasBeenInited = True

		# print "First Call"
		# import traceback
		# traceback.print_stack()

		return loggerNames
	else:
		print "LogInit Called Twice!"
		import traceback
		traceback.print_stack()
		raise


def initLogging(logLevel = logging.INFO, printLevel = logging.INFO):
	if not queVars.logHasBeenInited:
		mainLogger = logging.getLogger("Main")			# Main logger
		mainLogger.setLevel(logging.DEBUG)

		logDir		= "logs"
		logDir		= os.path.join(os.getcwd(), logDir)

		if not os.access(logDir, os.W_OK):
			try:
				os.mkdir(logDir)
			except:
				print "Error - cannot make log directory"
				print logDir
				raise

		subLogDir	= "Logs from - %s" % (time.strftime("%Y-%m-%d %H;%M;%S", time.gmtime()))

		logDir = os.path.join(logDir, subLogDir)

		if not os.access(logDir, os.W_OK):
			try:
				os.mkdir(logDir)
			except:
				print "Error - cannot make log directory"
				print logDir
				raise

		logHandler = RobustFileHandler(os.path.join(logDir, "journal.txt"))
		logHandler.setLevel(logLevel)
		formatter = logging.Formatter('%(asctime)s %(name)s %(levelname)s %(message)s')
		logHandler.setFormatter(formatter)

		mainLogger.addHandler(logHandler)

		errLogHandler = RobustFileHandler(os.path.join(logDir, "error.txt"))
		errLogHandler.setLevel(logging.ERROR)
		formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
		errLogHandler.setFormatter(formatter)

		critLogHandler = RobustFileHandler(os.path.join(logDir, "critical.txt"))
		critLogHandler.setLevel(logging.CRITICAL)
		formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
		critLogHandler.setFormatter(formatter)

		mainLogger.addHandler(errLogHandler)
		mainLogger.addHandler(critLogHandler)

		pl = logging.getLogger("Main.Plugin")		# SubLogger for Plugins

		pPrintHandler = PrintHandler()
		pPrintHandler.setLevel(printLevel)

		plFormatter = logging.Formatter('Plugin : %(levelname)s - %(message)s')
		pPrintHandler.setFormatter(plFormatter)
		pl.addHandler(pPrintHandler)

		mwl = logging.getLogger("Main.MainWin")		# and for the main App

		mPrintHandler = PrintHandler()
		mPrintHandler.setLevel(printLevel)

		mFormatter = logging.Formatter('MainWindow : %(levelname)s - %(message)s')
		mPrintHandler.setFormatter(mFormatter)
		mwl.addHandler(mPrintHandler)

		mwl = logging.getLogger("Main.Web")		# Lastly for the URL Retrieval script

		wPrintHandler = PrintHandler()
		wPrintHandler.setLevel(printLevel)

		wFormatter = logging.Formatter('WebGet : %(levelname)s - %(message)s')
		wPrintHandler.setFormatter(wFormatter)
		mwl.addHandler(wPrintHandler)

		queVars.logHasBeenInited = True



def clearThreadLog(logHandle):
	# detaches all locally instantiated log handlers, so that we don't get multiple prints from one call to xxx.log.info, etc...
	if queVars.logHasBeenInited:
		for loggerName in logHandle.logInstaces:
			tmpLogger = logging.getLogger(loggerName)
			for handler in tmpLogger.handlers:
				print handler
				tmpLogger.removeHandler(handler)
	queVars.logHasBeenInited = False
	queVars.threadLogHasBeenInited = False
